﻿using System;
using System.Collections.Generic;
using System.Web;
using Munq.LifetimeManagers;
using Munq;


namespace iMobileS.Common
{
    internal class RequestLifetimeManager : ILifetimeManager
    {
        private HttpContextBase _context;

        public RequestLifetimeManager()
        {
            if (HttpContext.Current != null)
            {
                this._context = new HttpContextWrapper(HttpContext.Current);
            }
        }

        public RequestLifetimeManager(HttpContextBase context)
        {
            this._context = context;
        }

        #region ILifetimeManager Members

        public object GetInstance(IRegistration registration)
        {
            object instance = _context.Items[registration.Key];
            if (instance == null)
            {
                instance = registration.CreateInstance();
                _context.Items[registration.Key] = instance;
            }

            return instance;
        }

        public void InvalidateInstanceCache(IRegistration registration)
        {
            _context.Items.Remove(registration.Key);
        }

        #endregion
    }

    internal class LocalThreadLifetimeManager : ILifetimeManager
    {
        [ThreadStatic]
        static IDictionary<string, object> localStorage;

        public object GetInstance(IRegistration registration)
        {
            object instance = null;

            // if it is a new thread then the localStorage needs to be initialized;
            if (localStorage == null)
                localStorage = new Dictionary<string, object>();

            if (!localStorage.TryGetValue(registration.Key, out instance))
            {
                instance = registration.CreateInstance();
                localStorage[registration.Key] = instance;
            }

            return instance;
        }

        public void InvalidateInstanceCache(IRegistration registration)
        {
            // nothing stored yet
            if (localStorage == null)
                return;

            localStorage.Remove(registration.Key);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class Services
    {
        #region Microsoft.Practices.Unity Container, which is replaced by Munq Container
        //------------------------------------------------------------------------------
        /*
         * Replaced by MUNQ
         */
        /*
        private static readonly IUnityContainer _container = new UnityContainer();
        public static void RegisterInstanceExternalLifetime<TInterface>(TInterface instance)
        {
            _container.RegisterInstance<TInterface>(instance, new ExternallyControlledLifetimeManager());
        }

        public static void RegisterInstanceExternalLifetime<TInterface>(string name, TInterface instance)
        {
            _container.RegisterInstance<TInterface>(name, instance, new ExternallyControlledLifetimeManager());
        }

        public static void RegisterInstancePerThread<TInterface>(TInterface instance)
        {
            _container.RegisterInstance(instance, new PerThreadLifetimeManager());
        }

        public static void RegisterInstancePerThread<TInterface>(string name, TInterface instance)
        {
            _container.RegisterInstance(name, instance, new PerThreadLifetimeManager());
        }

        public static void RegisterType<T>(params InjectionMember[] injectionMembers)
        {
            _container.RegisterType<T>(injectionMembers);
        }

        public static void RegisterType<TFrom, TTo>(params InjectionMember[] injectionMembers)
            where TTo : TFrom
        {
            _container.RegisterType<TFrom, TTo>(injectionMembers);
        }

        public static void RegisterType<TFrom, TTo>(string name, params InjectionMember[] injectionMembers)
            where TTo : TFrom
        {
            _container.RegisterType<TFrom, TTo>(name, injectionMembers);
        }

        public static void RegisterType<T>(string name, params InjectionMember[] injectionMembers)
        {
            _container.RegisterType<T>(name, injectionMembers);
        }

        public static void RegisterTypePerThread<T>(params InjectionMember[] injectionMembers)
        {
            _container.RegisterType<T>(new PerThreadLifetimeManager(), injectionMembers);
        }

        public static void RegisterTypePerThread<TFrom, TTo>(params InjectionMember[] injectionMembers)
            where TTo : TFrom
        {
            _container.RegisterType<TFrom, TTo>(new PerThreadLifetimeManager(), injectionMembers);
        }

        public static void RegisterTypePerThread<T>(string name, params InjectionMember[] injectionMembers)
        {
            _container.RegisterType<T>(name, new PerThreadLifetimeManager(), injectionMembers);
        }

        public static void RegisterTypePerThread<TFrom, TTo>(string name, params InjectionMember[] injectionMembers)
            where TTo : TFrom
        {
            _container.RegisterType<TFrom, TTo>(name, new PerThreadLifetimeManager(), injectionMembers);
        }

        public static T Get<T>()
        {
            return _container.Resolve<T>();
        }

        public static T Get<T>(string name)
        {
            return _container.Resolve<T>(name);
        }

        public static object Get(Type t)
        {
            return _container.Resolve(t);
        }

        public static object Get(Type t, string name)
        {
            return _container.Resolve(t, name);
        }

        public static IEnumerable<T> GetAll<T>()
        {
            return _container.ResolveAll<T>();
        }

        public static IEnumerable<object> GetAll(Type t)
        {
            return _container.ResolveAll(t);
        }

        public static void TearDown(object o)
        {
            _container.Teardown(o);
        }

        public static void InjectIntoConstructor<T>(params object[] parameters)
        {
            _container.Configure<InjectedMembers>().ConfigureInjectionFor<T>(new InjectionConstructor(parameters));
        }

        */
        //------------------------------------------------------------------------------

        #endregion Microsoft.Practices.Unity Container, which is replaced by Munq Container

        #region Fields

        private static readonly ILifetimeManager _containerLifetime = new ContainerLifetime();
        private static readonly IocContainer _container = new IocContainer();

        #endregion Fields

        #region Methods

        public static void Dispose()
        {
            if (null != _container)
                _container.Dispose();
        }

        public static IRegistration RegisterType<TType>(Func<IDependencyResolver, TType> register)
            where TType : class
        {

            return _container.Register<TType>(register);
        }

        public static IRegistration RegisterType(Type type, Func<IDependencyResolver, object> register)
        {
            return _container.Register(type, register);
        }

        /// <summary>
        /// Always return the same instances regardless of which lifetime manager is used
        /// </summary>
        /// <typeparam name="TType">Type of object which will be initialized</typeparam>
        /// <param name="register"></param>
        /// <returns></returns>
        public static IRegistration RegisterInstance<TType>(TType instance)
            where TType : class
        {
            return _container.RegisterInstance<TType>(instance)
                .WithLifetimeManager(_containerLifetime);
        }

        /// <summary>
        /// Always return the same instances regardless of which lifetime manager is used
        /// </summary>
        /// <typeparam name="TType">Type of object which will be initialized</typeparam>
        /// <param name="register"></param>
        /// <returns></returns>
        public static IRegistration RegisterInstance<TType>(TType instance, string addKey)
            where TType : class
        {
            return _container.RegisterInstance<TType>(addKey, instance)
                .WithLifetimeManager(_containerLifetime);
        }

        public static IRegistration RegisterTypeForLazyGet<TType>(Func<IDependencyResolver, TType> register)
        {
            Func<TType> lazyResolve = () => register(_container);
            return _container.RegisterInstance<Func<TType>>(lazyResolve);
        }

        public static TType Get<TType>()
            where TType : class
        {
            return _container.Resolve<TType>();
        }

        public static Func<TType> LazyGet<TType>()
            where TType : class
        {
            return _container.Resolve<Func<TType>>();
        }

        #endregion Methods
    }
}